package cn.lg.soar.common.util.jackson.annotations;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;

import java.io.IOException;
import java.lang.annotation.*;
import java.text.NumberFormat;
import java.util.Locale;

/**
 * 数值序列化
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
@JacksonAnnotationsInside
@JsonSerialize(using = NumberSerialize.Serializer.class)
public @interface NumberSerialize {

    Type value() default Type.NUMBER;

    String country() default "CN";

    String lang() default "zh";

    String variant() default "";

    public enum Type {
        /**
         * 百分比
         */
        PERCENT,
        /**
         * 货币
         */
        CURRENCY,
        /**
         * 数值
         */
        NUMBER,
        /**
         * 整数
         */
        INTEGER
    }

    class Serializer extends JsonSerializer<Number> implements ContextualSerializer {

        private NumberFormat format;

        public Serializer() {}

        public Serializer(Annotation annotation) {
            NumberSerialize a = (NumberSerialize) annotation;
            Locale locale = Locale.getDefault();
            locale = new Locale(
                    "".equals(a.lang()) ? locale.getLanguage() : a.lang(),
                    "".equals(a.country()) ? locale.getCountry() : a.country(),
                    "".equals(a.variant()) ? locale.getVariant() : a.variant()
            );
            switch (a.value()) {
                case INTEGER:
                    format = NumberFormat.getIntegerInstance(locale);
                    break;
                case PERCENT:
                    format = NumberFormat.getPercentInstance(locale);
                    break;
                case CURRENCY:
                    format = NumberFormat.getCurrencyInstance(locale);
                    break;
                default: format = NumberFormat.getNumberInstance(locale);
            }
        }

        @Override
        public void serialize(Number number, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            jsonGenerator.writeString(format.format(number));
        }

        @Override
        public JsonSerializer<?> createContextual(final SerializerProvider serializerProvider,
                                                  final BeanProperty beanProperty) throws JsonMappingException {
            if (beanProperty != null) {
                NumberSerialize annotation = beanProperty.getAnnotation(NumberSerialize.class);
                if (annotation == null) {
                    annotation = beanProperty.getContextAnnotation(NumberSerialize.class);
                }
                if (annotation != null) {
                    return new NumberSerialize.Serializer(annotation);
                }
                return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
            }
            return serializerProvider.findNullValueSerializer(null);
        }
    }
}
